//
//  DYPrinterManager.m
//  DYPrintSDK
//
//  Created by mr.ye on 2023/11/20.
//

#import "DYPrinterManager.h"
#import "DYPrintTaskCmd.h"
#import "DYPrintParse.h"
#import "DYPrintCmd.h"
@interface DYPrinterManager ()<CBPeripheralDelegate>
@property (nonatomic , assign) NSUInteger credit;
@property (nonatomic , assign) NSUInteger mtu;
//已发的字节数
@property (nonatomic , assign) NSUInteger sendLoc;
@property (nonatomic , assign) NSUInteger index;
@property (nonatomic , strong) dispatch_queue_t queue;

/// 浓度
@property (nonatomic , assign) NSUInteger thick;

//写入特征对象
@property (nonatomic , strong) CBCharacteristic *writeCht;

//接收特征对象
@property (nonatomic , strong) CBCharacteristic *writeWithoutRspCht;


//指令执行的回调
@property (nonatomic , strong) DYPrintTaskCmd *currentTask;

@property (nonatomic , copy) NSString *timeoutUUID;

@property (nonatomic , strong) NSTimer *timer;


//固件包数据
@property (nonatomic , strong) NSData *otaData;

//固件发送数据长度
@property (nonatomic , assign) NSUInteger otaSendLoc;


@property (nonatomic , copy) TaskCompelete otaCompelete;

//@property (nonatomic , strong)NSData * printData;

@end


@implementation DYPrinterManager

- (instancetype)initWithPeripheral:(CBPeripheral*)peripheral{
    if(self=[super init]){
        self.peripheral = peripheral;
        self.peripheral.delegate = self;
        self.queue = dispatch_queue_create("com.DYPrint.printer.sdk", DISPATCH_QUEUE_SERIAL);
        
        //开启寻找服务对象
        dispatch_async(self.queue, ^{
            CBUUID *uuid = [CBUUID UUIDWithString:@"FF00"];
            [self.peripheral discoverServices:@[uuid]];
        });
    }
    return self;
}
- (instancetype)init{
    if (self = [super init]) {
        self.credit = 0;
        self.sendLoc = 0;
    }
    return self;
}


#pragma mark - CBPeripheralDelegate
//发现服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error {
    for (CBService *service in peripheral.services) {
        [peripheral discoverCharacteristics:nil forService:service];
    }
}
//发现特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error {
    for (CBService *service in peripheral.services) {
        for (CBCharacteristic *cha in service.characteristics) {
            if ((cha.properties & CBCharacteristicPropertyWrite) && [service.UUID.UUIDString isEqualToString:@"FF00"]) {
                self.writeCht = cha;
            }
            if (cha.properties & CBCharacteristicPropertyNotify) {
                [peripheral setNotifyValue:YES forCharacteristic:cha];
            }
            if ((cha.properties & CBCharacteristicPropertyWriteWithoutResponse) && [service.UUID.UUIDString isEqualToString:@"FF00"]) {
                self.writeWithoutRspCht = cha;
            }
        }
    }
    
}

//特征更新
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    if (error) {
        NSLog(@"printer recive data error [%@]",error);
        return;
    }
    NSData *data = characteristic.value;
        NSLog(@"RECIVE DATA [%@]", data);
    [self didReciveData:data cht:characteristic];
}

//写入特征
- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    
    if (error) {
        NSLog(@"printer write data error [%@]", error);
    }
}

#pragma mark --selfAction---

//数据接收
- (void)didReciveData:(NSData *)data cht:(CBCharacteristic *)characteristic {
    
   
    
    
    Byte list[data.length];
    [data getBytes:&list length:data.length];
    //FF03是流控信息
    if ([characteristic.UUID.UUIDString isEqualToString:@"FF03"]) {
        //可以发几次包
        NSUInteger credit = [DYPrintParse creditWithData:data];
        if (credit > 0) {
            self.credit = self.credit + credit;
            NSLog(@"更新信号值%ld", self.credit);
            dispatch_async(self.queue, ^{
                [self writeDataWhenRefreshCredit];
            });
            return;
        }
        
        //每次可发的字节
        NSUInteger mtu = [DYPrintParse mtuWithData:data];
        if (mtu > 0) {
            self.mtu = mtu;
            NSLog(@"更新信号包 [%lu]", self.mtu);
            return;
        }
        return;
    }
    
    //打印出问题
    NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    if ([msg hasPrefix:@"er"]) {
        NSError *error = [NSError errorWithDomain:@"DYPrint.SDK"
                                             code:-1001
                                         userInfo:@{NSLocalizedDescriptionKey: @"打印出错了"}];
        self.currentTask.compelete(error,-1000);
        return;
    }
    

    NSLog(@"接收----%@----%@",data,characteristic.UUID.UUIDString);
    
    //解析回调状态
    if(self.currentTask.parse){
        NSObject *obj = self.currentTask.parse(data);
        if (obj) {
            TaskCompelete compelete = self.currentTask.compelete;
            self.currentTask = nil;
            compelete(obj,1000);
        }
    }
    
    
    
    
}
//信号处理，分包发送
- (void)writeDataWhenRefreshCredit {
    // 没有数据结束
    if (!self.currentTask) {
        NSLog(@"没有数据需要打印");
        return;
    }
    // 数据发送完成
    if (self.sendLoc >= self.currentTask.data.length) {
        NSLog(@"发送完毕");
        if (!self.currentTask.parse) {
            NSLog(@"销毁任务");
            TaskCompelete cmp = self.currentTask.compelete;
            self.currentTask = nil;
            if (cmp) {
                cmp(nil,1000);
            }
        }
        return;
    }
    
    // 没有credit暂停
    if (self.credit <= 0) {
        NSLog(@"信号值小于0");
        return;
    }
    
    
    NSUInteger mtu = self.mtu;
    if (mtu == 0) {
        NSLog(@"MTU小余0");
        return;
    }
    NSUInteger unSendLen = self.currentTask.data.length - self.sendLoc;
    NSUInteger len = MIN(unSendLen, mtu);
    NSData *shouldSendData = [self.currentTask.data subdataWithRange:NSMakeRange(self.sendLoc, len)];
    [self writeData:shouldSendData withResp:NO];
    self.sendLoc = self.sendLoc + len;
    [self writeDataWhenRefreshCredit];
}

//其他指令回调（分包）
- (void)sendTask:(DYPrintTaskCmd *)task {
    if (self.currentTask) {
        NSError *error = [NSError errorWithDomain:@"DYPrint.SDK"
                                             code:-1001
                                         userInfo:@{NSLocalizedDescriptionKey: @"当前有任务在执行"}];
        task.compelete(error,-1001);;
        return;
    }
    
    dispatch_async(self.queue, ^{
        self.sendLoc = 0;
        self.currentTask = task;
        [self writeDataWhenRefreshCredit];
    });
}



//写入数据
- (void)writeData:(NSData *)data withResp:(BOOL)isResp {
    self.credit = self.credit - 1;
    if (isResp) {
        [self.peripheral writeValue:data forCharacteristic:self.writeCht type:CBCharacteristicWriteWithResponse];
    }else{
        [self.peripheral writeValue:data forCharacteristic:self.writeWithoutRspCht type:CBCharacteristicWriteWithoutResponse];
    }
}


#pragma mark ----公开方法----
//检查打印状态
-(void)checkPrintStates:(void (^)(LuckBLEManagerStatus))callback{
    DYPrintTaskCmd * cmd =  [DYPrintTaskCmd getStateTaskCompelete:^(id  _Nullable obj, NSUInteger code) {
        
        LuckBLEManagerStatus status = [obj integerValue];
        callback(status);
        
    }];
    [self sendTask:cmd];

    
}
//发送长数据
- (void)sendPrintDataCompelete:(void(^)(id obj,NSUInteger code))compelete  data:(NSData*)data {
    DYPrintTaskCmd * cmd = [[DYPrintTaskCmd alloc]init];
    cmd.data = data;
    cmd.parse =  ^NSObject *(NSData *data) {
        BOOL compelete = [DYPrintParse imageCompeleteWithData:data];
        return compelete ? @(compelete) : nil;
    };
    cmd.compelete = compelete;
    
    [self sendTask:cmd];
    
}

//获取打印机器的信息
- (void)getPrinterInfo:(TaskCompelete)callback{
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd getBaseInfoCmd:^(NSMutableDictionary *  obj, NSUInteger code) {
        [obj setValue:self.peripheral.name forKey:@"name"];
        callback(obj,1000);
    }];
    [self sendTask:cmd];
    
}

//获取关机时间
-(void)getShutTime:(TaskCompelete)compelete {
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd getShutTimeCmd:^(id   obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//获取打印机型号
-(void)getMode:(TaskCompelete)compelete{
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd getModeCmd:^(id  obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//获取打印机型号
-(void)getPrintColor:(TaskCompelete)compelete{
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd getPrintColorCmd:^(id  obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//设置关机时间
-(void)setShutTime:(TaskCompelete)compelete time:(NSInteger)time{
    DYPrintTaskCmd * cmd =  [DYPrintTaskCmd setShutTimeCmd:time compelete:^(id  _Nullable obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}


//设置颜色
-(void)setPrintColor:(TaskCompelete)compelete color:(NSInteger)color{
    DYPrintTaskCmd * cmd =  [DYPrintTaskCmd setColorCmd:color compelete:^(id  _Nullable obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//设置纸张类
-(void)setPaperType:(TaskCompelete)compelete paper:(DYPrintPaperType)type{
    DYPrintTaskCmd * cmd =  [DYPrintTaskCmd setPaperTypeCmd:type compelete:^(id  _Nullable obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//设置定位纸张类型
-(void)setPositionPaper:(TaskCompelete)compelete paper:(DYPrintPaperType)type{
    DYPrintTaskCmd * cmd =  [DYPrintTaskCmd setPaperPostionCmd:type compelete:^(id  _Nullable obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//纸张退纸
-(void)setPaperBack:(TaskCompelete)compelete{
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd returePaperCompelete:^(id  _Nullable obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
-(void)enterPaper:(TaskCompelete)compelete{
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd enterPaperCompelete:^(id  _Nullable obj, NSUInteger code) {
        compelete(obj,1000);
    }];
    [self sendTask:cmd];
}
//更新固件
- (void)updateVersion:(NSData *)versionData callback:(nullable void(^)(NSError *error))callback
                 once:(void(^)(bool isOK))onceCall {
    self.otaSendLoc = 0;
    self.otaData = versionData;
    __weak DYPrinterManager *weakself = self;
    self.otaCompelete = ^(NSObject * _Nullable obj , NSUInteger code) {
        NSLog(@"otaLoopCompelete");
        //升级成功需要重新启动打印机
        DYPrintTaskCmd * cmd = [DYPrintTaskCmd commentCmd:^(id  _Nullable obj, NSUInteger code) {
            NSLog(@"升级成功");
            callback(nil);
        } data:[DYPrintCmd restartPrinter]];
        [weakself sendTask:cmd];
    };
    
    //检查状态
    [self checkPrintStates:^(LuckBLEManagerStatus state) {
        //繁忙
        if(state ==DYBLEManagerStatusPrinting ||  state ==DYBLEManagerStatusBusy){
            NSError * erro = [NSError errorWithDomain:@"com.luck.sdk" code:-1000 userInfo:@{NSLocalizedDescriptionKey:@"状态异常"}];
            callback(erro);
            NSLog(@"状态繁忙");
            return;
        }
        
        dispatch_async(self.queue, ^{
    
            //开始升级
            [weakself sendTask:[DYPrintTaskCmd commentCmd:^(id  _Nullable obj, NSUInteger code) {
                NSLog(@"开始升级");
                //搜素设备
                [weakself sendTask:[DYPrintTaskCmd commentCmd:^(id  _Nullable obj, NSUInteger code) {
                    NSLog(@"搜索设备");
                    //清除缓存
                    [weakself sendPrintDataCompelete:^(id  _Nullable obj, NSUInteger code) {
                        NSLog(@"清理缓存");
                        [weakself writeUpdateOtaData:onceCall];
                        
                    } data:[DYPrintCmd cleanMemory:versionData]];
                    
                    
                    
                } data:[DYPrintCmd searchWillUpdate]]];
                
                
                
            } data:[DYPrintCmd willUpdate]]];
            
        });
        
        
        
    }];

}

//写入更新数据
- (void)writeUpdateOtaData:(void(^)(bool isOK))onceCall{

    NSLog(@"写入数据 [%lu], total [%lu]", self.otaSendLoc, self.otaData.length);
    if (self.otaSendLoc >= self.otaData.length) {
        
        if (self.otaCompelete) {
            self.otaCompelete(@"OK", 1000);
        }
        return;
    }
    
    __weak DYPrinterManager *weakself = self;
    DYPrintTaskCmd * cmd = [DYPrintTaskCmd sendUpdateDataTask:self.otaData loc:self.otaSendLoc compelete:^(id  _Nullable obj, NSUInteger code) {
        weakself.otaSendLoc += 255;
        onceCall(YES);
        [weakself writeUpdateOtaData:onceCall];

        
    }];
    [self sendTask:cmd];
    

    
}



@end
